--客户端用的network

local skynet = require "skynet"
local socket = require "skynet.socket"
local MessagePack = require "MessagePack"
local cjson = require "cjson"

local Network = class("Network")

function Network:ctor(ip,port)
    self.fd = nil
    self.last_package = ""
    self.msg_callbacks = {} --消息回调列表
    self.message_pack = MessagePack.new()
    self:open(ip,port)
end

---------------------------------------------------------
-- private
---------------------------------------------------------
--取大端2个字节
function Network:readShortBig( text ) --big endian
    return text:byte(1)*256 + text:byte(2)
end

--包长度2字节
function Network:unpackPackage(text)
    local size = #text
    if size < 2 then
        return nil, text
    end
    local pack_size = self:readShortBig(text)
    if size < pack_size + 2 then
        return nil, text
    end
    local offset = 2
    local msg = text:sub(offset + 1, offset + pack_size)
    local last = text:sub(offset + 1 + pack_size)
    return msg, last
end


--组装json包
function Network:encodeJsonMsg(pack_id, msg_body)
    local msgbody
    if next(msg_body) then
        msgbody = cjson.encode(msg_body)
        if not msgbody then
            log.error('encode json msg body failed')
            return
        end
    else
        msgbody = ''
    end
    --http://cloudwu.github.io/lua53doc/manual.html#6.4.2
    local msg = string.pack(">H", pack_id)..msgbody
    if msg == nil then
        log.error('msg pack failed'..pack_id)
        return
    end
    return msg
end

--连接socket
function Network:open(ip, port)
    if not ip or not port then 
        print("ip port is nill___")
        return 
    end
    self.fd = socket.open(ip, port)
    if not self.fd then
        print("连接 "..ip..":"..port.."失败")
        return
    end
    skynet.fork(function() self:recvLoop() end)
    print("########连接"..ip..":"..port.."成功#########")
end

function Network:close()
    print("____________Network close__________",self.fd)
    if self.fd then 
        socket.close(self.fd)
    end
    self.fd = nil
    self.last_package = ""
    -- self:dispatchMessage("socket_close")
    -- skynet.exit()
end

-- function Network:redirect(ip, port)
--     --local handler = self.handler
--     self:close()
--     self:open(ip, port)
--     if not self.fd then
--         print("连接 "..ip..":"..port.."失败")
--         return false
--     end
--     --self.handler = handler
--     print("连接"..ip..":"..port.."成功")
--     return true
-- end

--接收消息
function Network:recvLoop()
    while true do
        --print(">>>M:recv_loop>>>")
        if not self.fd then
            print("接收数据协程结束")
            return
        end
        local str = socket.read(self.fd)
        if str then
            self:receive(str)
        else
            print("接收数据错误协程结束")
            self:close()
            return
        end
    end
end

function Network:receive(str)
    -- print("收到数据"..#str)
    self.last_package = self.last_package .. str
    local msg
    local command
    while #self.last_package > 0 do
        msg, self.last_package = self:unpackPackage(self.last_package)
        if not msg then
            break 
        end
        local ok, message_id, pack_name, pack_body = pcall(handler(self.message_pack,self.message_pack.unpackClient), msg)        
        if not ok then
            print("message dispatch error: "..tostring(pack_body))
        else
            self:dispatchMessage(pack_name, pack_body)           
        end
    end
end


---------------------------------------------------------
-- public
---------------------------------------------------------

--发送
function Network:send(message_name, body)
    -- print("________send___",message_name)
    self.message_pack:send(self.fd, nil, message_name, body)
end

--发送josn
function Network:sendJson(data)
    for k,v in pairs(data) do 
        local pack =  10000
        if not pack then
            print('send message faild no found msg_name:',msg_name,k)
            return
        end
        local msg = self:encodeJsonMsg(pack, v)
        print("___",msg)
        -- msg = self:encryptData(msg)
        if msg then
            -- return self:writePackage(msg)
        else
            print('write_package faild :',k)
        end
    end    
end

--注册消息回调
function Network:register(name, callback)    
    self.msg_callbacks[name] = callback
end

--消息派发
function Network:dispatchMessage(pack_name, pack_body)
    local func = self.msg_callbacks[pack_name]
    if not func then 
        print("########### Network dispatchMessage not found message func ",pack_name)
        return
    end
    local ok, err = xpcall(func, debug.traceback, pack_body)
    if not ok then
        print("dispatch error__", err)
    end
end


return Network
